package com.niiwoo.civet.trade.service.local.creditor;

import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.fastjson.JSON;
import com.dangdang.ddframe.rdb.sharding.api.HintManager;
import com.dangdang.ddframe.rdb.sharding.hint.HintManagerHolder;
import com.niiwoo.activity.stage.dto.request.prize.PrizeToBackedForCreditorSaleReqDTO;
import com.niiwoo.activity.stage.dto.request.project.ProjectRaiseRateCreditorReqDTO;
import com.niiwoo.activity.stage.enums.prize.UserPrizeTypeIdEnum;
import com.niiwoo.activity.stage.service.prize.ActivityPrizeDubboService;
import com.niiwoo.activity.stage.service.project.ProjectRaiseRateDubboService;
import com.niiwoo.civet.account.dto.request.CreditorTransferSuccessAccountingRequestDTO;
import com.niiwoo.civet.account.service.CreditorTransferDubboService;
import com.niiwoo.civet.trade.constant.AccountConfigConstants;
import com.niiwoo.civet.trade.constant.MqConstant;
import com.niiwoo.civet.trade.dao.entity.*;
import com.niiwoo.civet.trade.dao.mapper.*;
import com.niiwoo.civet.trade.dto.common.BathTransactionNotifyDTO;
import com.niiwoo.civet.trade.enums.*;
import com.niiwoo.civet.trade.enums.FadadaContractEnum.TradeTypeEnum;
import com.niiwoo.civet.trade.enums.FadadaContractTemplateEnum.TemplateTypeEnum;
import com.niiwoo.civet.trade.enums.creditorSale.SaleDetailStatusEnum;
import com.niiwoo.civet.trade.service.local.contract.CreditorTransferContract;
import com.niiwoo.civet.trade.service.local.contract.FadadaContractContext;
import com.niiwoo.civet.trade.service.local.lend.ProjectLendLocalService;
import com.niiwoo.civet.trade.service.local.refund.CommonLocalService;
import com.niiwoo.civet.trade.utils.RepaymentUtil;
import com.niiwoo.tripod.lanmao.component.LanMaoDirectService;
import com.niiwoo.tripod.lanmao.component.LanMaoSequence;
import com.niiwoo.tripod.lanmao.enums.*;
import com.niiwoo.tripod.lanmao.request.AsyncTransactionRequest;
import com.niiwoo.tripod.lanmao.request.QueryTransactionRequest;
import com.niiwoo.tripod.lanmao.response.AsyncTransactionResponse;
import com.niiwoo.tripod.lanmao.response.QueryTransactionResponse;
import com.niiwoo.tripod.provider.exception.BizException;
import com.niiwoo.tripod.service.component.SnowflakeIdWorker;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.FastDateFormat;
import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronizationAdapter;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.util.Assert;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

@Service
public class CreditorTransferConfirmLocalService {

	private static final Logger logger = LoggerFactory.getLogger(CreditorTransferConfirmLocalService.class);

	@Autowired
	private ProjectMapperExt projectMapperExt;

	@Autowired
	private ProjectInvestOrderMapperExt projectInvestOrderMapperExt;

	@Autowired
	private SnowflakeIdWorker snowflakeIdWorker;

	@Autowired
	private LanMaoSequence lanMaoSequence;

	@Autowired
	private RabbitTemplate consistencyRabbitTemplate;

	@Autowired
	private FadadaContractContext fadadaContractContext;

	@Autowired
	private ProjectContractMapperExt projectContractMapperExt;

	@Autowired
	private LanMaoDirectService lanMaoDirectService;

	@Autowired
	private CreditorTransferConfirmOrderDetailMapperExt creditorTransferConfirmOrderDetailMapperExt;

	@Autowired
	private CreditorTransferConfirmOrderDetailBizMapperExt creditorTransferConfirmOrderDetailBizMapperExt;

	@Autowired
	private ProjectInvestorPlanMapperExt projectInvestorPlanMapperExt;

	@Autowired
	private CreditorSaleDetailMapperExt creditorSaleDetailMapperExt;

	@Autowired
	private AccountConfigMapper accountConfigMapper;

	@Autowired
	private ProjectLendLocalService projectLendLocalService;

	@Autowired
    private InvestorCreditorMapperExt investorCreditorMapperExt;

	@Autowired
	private CommonLocalService commonLocalService;

	@Reference(version = "1.0.0")
	private CreditorTransferDubboService creditorTransferDubboService;

	@Autowired
	private CreditorTransferContract creditorTransferContract;

	@Reference(version = "1.0.0")
	private ActivityPrizeDubboService activityPrizeDubboService;

	@Reference(version = "1.0.0")
	private ProjectRaiseRateDubboService projectRaiseRateDubboService;


	/**
	 * 生成债转确认订单
	 *
	 * @param creditorSaleDetailId
	 * @return
	 */
	@Transactional
	public AsyncTransactionRequest buildCreditorTransferConfirmOrder(Long creditorSaleDetailId, String creditorSaleUserId) {
		logger.info("生成债转确认订单 creditorSaleDetailId:{}", creditorSaleDetailId);
		CreditorSaleDetail creditorSaleDetail = creditorSaleDetailMapperExt.selectByPrimaryKeyAndSaleUserId(creditorSaleDetailId, creditorSaleUserId);
		ProjectInvestOrder projectInvestOrder = projectInvestOrderMapperExt.queryInvestSuccessfulByCreditorSaleDetailId(creditorSaleDetailId);

        CreditorSaleDetail updateCreditorSaleDetail = new CreditorSaleDetail();
		updateCreditorSaleDetail.setId(creditorSaleDetailId);
		updateCreditorSaleDetail.setUserId(creditorSaleUserId);
		updateCreditorSaleDetail.setStatus(SaleDetailStatusEnum.CONFIRM_CREDIT_ASSIGNMENT_HANDING.getValue());
		updateCreditorSaleDetail.setUpdateTime(new Date());
		creditorSaleDetailMapperExt.updateByPrimaryKeyAndUserIdSelective(updateCreditorSaleDetail);

        Map<Long, String> investOrderIdRequestNoMap = projectLendLocalService.queryInvestRequestNo(Arrays.asList(projectInvestOrder));
		if (investOrderIdRequestNoMap.get(projectInvestOrder.getId()) == null) {
			throw new BizException("TRD_700005", "投资订单对应银行存管requestNo为空，projectInvestOrderId:" + projectInvestOrder.getId());
		}

		String batchNo = lanMaoSequence.getBatchNo();

		// 债转确认订单明细
		CreditorTransferConfirmOrderDetail creditorTransferConfirmOrderDetail = new CreditorTransferConfirmOrderDetail();
		creditorTransferConfirmOrderDetail.setId(snowflakeIdWorker.nextId());
		creditorTransferConfirmOrderDetail.setBatchNo(batchNo);
		creditorTransferConfirmOrderDetail.setProjectId(creditorSaleDetail.getProjectId());
		creditorTransferConfirmOrderDetail.setDetailRequestNo(lanMaoSequence.getRequestNo());
		creditorTransferConfirmOrderDetail.setCreditorSaleUserId(creditorSaleDetail.getUserId());
		creditorTransferConfirmOrderDetail.setCreditorSaleDetailId(creditorSaleDetailId);
		creditorTransferConfirmOrderDetail.setCreditorSaleRequestNo(creditorSaleDetail.getRequestNo());
		creditorTransferConfirmOrderDetail.setStatus(CreditorTransferConfirmStatusEnum.HANDLING.getValue());
		creditorTransferConfirmOrderDetail.setCreateTime(new Date());
		creditorTransferConfirmOrderDetail.setUpdateTime(new Date());
		creditorTransferConfirmOrderDetail.setAmountTotal(projectInvestOrder.getAmount());
		creditorTransferConfirmOrderDetail.setNumTotal(1);
		creditorTransferConfirmOrderDetailMapperExt.insertSelective(creditorTransferConfirmOrderDetail);

		// 债转确认订单业务明细
		CreditorTransferConfirmOrderDetailBiz creditorTransferConfirmOrderDetailBiz = new CreditorTransferConfirmOrderDetailBiz();
		creditorTransferConfirmOrderDetailBiz.setId(snowflakeIdWorker.nextId());
		creditorTransferConfirmOrderDetailBiz.setDetailRequestNo(creditorTransferConfirmOrderDetail.getDetailRequestNo());
		creditorTransferConfirmOrderDetailBiz.setBizType(BusinessTypeEnum.CREDIT_ASSIGNMENT.getValue());
		creditorTransferConfirmOrderDetailBiz.setFreezeRequestNo(investOrderIdRequestNoMap.get(projectInvestOrder.getId()));
		creditorTransferConfirmOrderDetailBiz.setInvestOrderId(projectInvestOrder.getId());
		creditorTransferConfirmOrderDetailBiz.setSourceUserId(projectInvestOrder.getUserId());
		creditorTransferConfirmOrderDetailBiz.setSourceAccountId(projectInvestOrder.getAccountId());
		creditorTransferConfirmOrderDetailBiz.setSourcePlatformUserNo(projectInvestOrder.getPlatformUserNo());
		creditorTransferConfirmOrderDetailBiz.setTargetUserId(creditorSaleDetail.getUserId());
		creditorTransferConfirmOrderDetailBiz.setTargetAccountId(creditorSaleDetail.getAccountId());
		creditorTransferConfirmOrderDetailBiz.setTargetPlatformUserNo(creditorSaleDetail.getPlatformUserNo());
		creditorTransferConfirmOrderDetailBiz.setAmount(projectInvestOrder.getAmount());
		creditorTransferConfirmOrderDetailBiz.setShare(projectInvestOrder.getShare());
		creditorTransferConfirmOrderDetailBiz.setCreateTime(new Date());
		creditorTransferConfirmOrderDetailBiz.setUpdateTime(new Date());
		creditorTransferConfirmOrderDetailBizMapperExt.insertSelective(creditorTransferConfirmOrderDetailBiz);

		List<AsyncTransactionRequest.BizDetail> bizDetailList = new ArrayList<>();
		AsyncTransactionRequest.BizDetail bizDetail = new AsyncTransactionRequest.BizDetail();
		bizDetail.setRequestNo(creditorTransferConfirmOrderDetail.getDetailRequestNo());
		bizDetail.setTradeType(TransactionTypeEnum.CREDIT_ASSIGNMENT);
		bizDetail.setProjectNo(creditorTransferConfirmOrderDetail.getProjectId() + "");
		bizDetail.setSaleRequestNo(creditorTransferConfirmOrderDetail.getCreditorSaleRequestNo());

		List<AsyncTransactionRequest.BizDetail.BusinessDetail> businessDetailList = new ArrayList<>();

		AsyncTransactionRequest.BizDetail.BusinessDetail businessDetail = new AsyncTransactionRequest.BizDetail.BusinessDetail();
		BusinessTypeEnum bizType = BusinessTypeEnum.enumOf(creditorTransferConfirmOrderDetailBiz.getBizType());
		businessDetail.setBizType(bizType);
		businessDetail.setFreezeRequestNo(creditorTransferConfirmOrderDetailBiz.getFreezeRequestNo());
		businessDetail.setSourcePlatformUserNo(creditorTransferConfirmOrderDetailBiz.getSourcePlatformUserNo());
		businessDetail.setTargetPlatformUserNo(creditorTransferConfirmOrderDetailBiz.getTargetPlatformUserNo());
		businessDetail.setAmount(creditorTransferConfirmOrderDetailBiz.getAmount());
		businessDetail.setShare(creditorTransferConfirmOrderDetailBiz.getShare());

		businessDetailList.add(businessDetail);



		//手续费
		if (creditorSaleDetail.getExpenseAmount().add(creditorSaleDetail.getSellingExpenseAmount()).compareTo(BigDecimal.ZERO) > 0){
			AccountConfig accountConfig = accountConfigMapper.selectByPrimaryKey(AccountConfigConstants.getPlatform());

			CreditorTransferConfirmOrderDetailBiz saleExpenseOrderDetailBiz = new CreditorTransferConfirmOrderDetailBiz();
			saleExpenseOrderDetailBiz.setId(snowflakeIdWorker.nextId());
			saleExpenseOrderDetailBiz.setDetailRequestNo(creditorTransferConfirmOrderDetail.getDetailRequestNo());
			saleExpenseOrderDetailBiz.setBizType(BusinessTypeEnum.COMMISSION.getValue());
			saleExpenseOrderDetailBiz.setFreezeRequestNo(investOrderIdRequestNoMap.get(projectInvestOrder.getId()));
			saleExpenseOrderDetailBiz.setSourceUserId(creditorSaleDetail.getUserId());
			saleExpenseOrderDetailBiz.setSourceAccountId(creditorSaleDetail.getAccountId());
			saleExpenseOrderDetailBiz.setSourcePlatformUserNo(creditorSaleDetail.getPlatformUserNo());
			saleExpenseOrderDetailBiz.setTargetAccountId(accountConfig.getAccountId());
			saleExpenseOrderDetailBiz.setTargetPlatformUserNo(accountConfig.getPlatformUserNo());
			saleExpenseOrderDetailBiz.setTargetUserId(accountConfig.getUserId());
			saleExpenseOrderDetailBiz.setAmount(creditorSaleDetail.getExpenseAmount().add(creditorSaleDetail.getSellingExpenseAmount()));
			saleExpenseOrderDetailBiz.setCreateTime(new Date());
			saleExpenseOrderDetailBiz.setUpdateTime(new Date());
			creditorTransferConfirmOrderDetailBizMapperExt.insertSelective(saleExpenseOrderDetailBiz);

			AsyncTransactionRequest.BizDetail.BusinessDetail saleExpenseBusinessDetail = new AsyncTransactionRequest.BizDetail.BusinessDetail();
			BusinessTypeEnum saleExpenseBizType = BusinessTypeEnum.enumOf(saleExpenseOrderDetailBiz.getBizType());
			saleExpenseBusinessDetail.setBizType(saleExpenseBizType);
			saleExpenseBusinessDetail.setFreezeRequestNo(saleExpenseOrderDetailBiz.getFreezeRequestNo());
			saleExpenseBusinessDetail.setSourcePlatformUserNo(saleExpenseOrderDetailBiz.getSourcePlatformUserNo());
			saleExpenseBusinessDetail.setTargetPlatformUserNo(saleExpenseOrderDetailBiz.getTargetPlatformUserNo());
			saleExpenseBusinessDetail.setAmount(saleExpenseOrderDetailBiz.getAmount());

			businessDetailList.add(saleExpenseBusinessDetail);
		}

		bizDetail.setDetails(businessDetailList);
		bizDetailList.add(bizDetail);

		// 银行存管业务明细
		AsyncTransactionRequest asyncTransactionRequest = new AsyncTransactionRequest();
		asyncTransactionRequest.setBatchNo(batchNo);
		asyncTransactionRequest.setBizDetails(bizDetailList);
		logger.info("生成债转确认订单 creditorSaleDetailId:{}, asyncTransactionRequest:{}", creditorSaleDetailId, JSON.toJSON(asyncTransactionRequest));
		return asyncTransactionRequest;
	}

	/**
	 * 债转确认结果通知
	 * @param creditorTransferConfirmNotifyDTOList
	 */
	public void creditorTransferConfirmResultNotify(List<BathTransactionNotifyDTO> creditorTransferConfirmNotifyDTOList){
		Assert.notNull(creditorTransferConfirmNotifyDTOList, "creditorTransferConfirmResultNotify creditorTransferConfirmNotifyDTOList is null.");
		for(BathTransactionNotifyDTO bathTransactionNotifyDTO : creditorTransferConfirmNotifyDTOList) {
			Assert.notNull(bathTransactionNotifyDTO, "creditorTransferConfirmResultNotify bathTransactionNotifyDTO is null.");
			logger.info("creditorTransferConfirmResultNotify detailRequestNo:{}, bathTransactionNotifyDTO:{}", bathTransactionNotifyDTO.getAsyncRequestNo(), JSON.toJSON(bathTransactionNotifyDTO));
			((CreditorTransferConfirmLocalService)AopContext.currentProxy()).creditorTransferConfirmResultNotify(bathTransactionNotifyDTO);
		}
	}

	@Transactional
	public void creditorTransferConfirmResultNotify(BathTransactionNotifyDTO bathTransactionNotifyDTO){
		CreditorTransferConfirmOrderDetail creditorTransferConfirmOrderDetail = creditorTransferConfirmOrderDetailMapperExt.queryCreditorTransferConfirmOrderDetailByDetailRequestNo(bathTransactionNotifyDTO.getAsyncRequestNo());
		Assert.notNull(creditorTransferConfirmOrderDetail, "creditorTransferConfirmResultNotify creditorTransferConfirmOrderDetail is null, detailRequestNo=" + bathTransactionNotifyDTO.getAsyncRequestNo());
		creditorTransferConfirmOrderDetail = creditorTransferConfirmOrderDetailMapperExt.selectByPrimaryKeyForUpdate(creditorTransferConfirmOrderDetail.getId());
		if (!creditorTransferConfirmOrderDetail.getStatus().equals(CreditorTransferConfirmStatusEnum.HANDLING.getValue())) {
			// 订单状态已经被修改,此订单已经被处理过 后续操作中断
			logger.info("creditorTransferConfirmResultNotify creditorTransferConfirmOrderDetail status not eq HANDLING. detailRequestNo:{}, status:{}", bathTransactionNotifyDTO.getAsyncRequestNo(), creditorTransferConfirmOrderDetail.getStatus());
			return;
		}
		logger.info("更新债转确认明细表状态 creditorSaleDetailId:{}, detailRequestNo:{}, status:{}", creditorTransferConfirmOrderDetail.getCreditorSaleDetailId(), bathTransactionNotifyDTO.getAsyncRequestNo(), bathTransactionNotifyDTO.getStatus());

		CreditorTransferConfirmOrderDetail updateRecord = new CreditorTransferConfirmOrderDetail();
		updateRecord.setId(creditorTransferConfirmOrderDetail.getId());
		updateRecord.setStatus(CreditorTransferConfirmStatusEnum.valueOf(bathTransactionNotifyDTO.getStatus()).getValue());
		if (CreditorTransferConfirmStatusEnum.FAIL.name().equals(bathTransactionNotifyDTO.getStatus())) {
			updateRecord.setErrorCode(bathTransactionNotifyDTO.getErrorCode());
			updateRecord.setErrorMessage(bathTransactionNotifyDTO.getErrorMessage());
			// 债转确认失败,终止后续操作
			logger.warn("银行存管返回状态为处理失败 bathTransactionNotifyDTO: {}", JSON.toJSON(bathTransactionNotifyDTO));
		}
		creditorTransferConfirmOrderDetailMapperExt.updateByPrimaryKeySelective(updateRecord);

		if (CreditorTransferConfirmStatusEnum.SUCCESS.name().equals(bathTransactionNotifyDTO.getStatus())) {
			logger.info("接收到银行债转确认成功通知 creditorSaleDetailId:{}; batchNo:{}; detailRequestNo:{}", creditorTransferConfirmOrderDetail.getCreditorSaleDetailId(),
					creditorTransferConfirmOrderDetail.getBatchNo(), creditorTransferConfirmOrderDetail.getDetailRequestNo());

			// 更新债转出让状态与记账状态
			CreditorSaleDetail creditorSaleDetail = new CreditorSaleDetail();
			creditorSaleDetail.setId(creditorTransferConfirmOrderDetail.getCreditorSaleDetailId());
			creditorSaleDetail.setUserId(creditorTransferConfirmOrderDetail.getCreditorSaleUserId());
			creditorSaleDetail.setStatus(SaleDetailStatusEnum.SALE_SUCCESS.getValue());
			creditorSaleDetail.setAccountingStatus(CreditorTransferConfirmStatusEnum.HANDLING.getValue()); // 记账状态修改为处理中
			creditorSaleDetail.setSellerInvestPrizeStatus(CreditorTransferConfirmStatusEnum.HANDLING.getValue()); // 债权出让人投资红包状态修改为处理中
			creditorSaleDetail.setSellerProjectActivityRaiseInterestStatus(CreditorTransferConfirmStatusEnum.HANDLING.getValue()); // 债权出让人标的加息状态修改为处理中
			creditorSaleDetail.setSuccessTime(new Date());
			creditorSaleDetail.setUpdateTime(new Date());
			creditorSaleDetailMapperExt.updateByPrimaryKeyAndUserIdSelective(creditorSaleDetail);

			creditorSaleDetail = creditorSaleDetailMapperExt.selectByPrimaryKeyAndSaleUserId(creditorTransferConfirmOrderDetail.getCreditorSaleDetailId(), creditorTransferConfirmOrderDetail.getCreditorSaleUserId());

			// 源投资订单投资订单衍变状态修改为已转让
			ProjectInvestOrder originProjectInvestOrder = new ProjectInvestOrder();
			originProjectInvestOrder.setId(creditorSaleDetail.getInvestOrderId());
			originProjectInvestOrder.setEvolutionStatus(Byte.valueOf("7"));
			projectInvestOrderMapperExt.updateByPrimaryKeySelective(originProjectInvestOrder);


			ProjectInvestOrder projectInvestOrder = projectInvestOrderMapperExt
					.queryInvestSuccessfulByCreditorSaleDetailId(creditorTransferConfirmOrderDetail.getCreditorSaleDetailId());

			// 更新投资订单状态
			ProjectInvestOrder updateProjectInvestOrderRecord = new ProjectInvestOrder();
			updateProjectInvestOrderRecord.setId(projectInvestOrder.getId());
			updateProjectInvestOrderRecord.setEvolutionStatus(ProjectInvestOrderEvolutionStatusEnum.BACKING
					.getValue());
			updateProjectInvestOrderRecord.setFullSuccessTime(creditorSaleDetail.getSuccessTime());
			projectInvestOrderMapperExt.updateByPrimaryKeySelective(updateProjectInvestOrderRecord);


			// 变更回款计划和投资人债权
			List<ProjectInvestorPlan> projectInvestorPlanList = changeInvestorPlanAndInvestorCreditor(creditorSaleDetail, projectInvestOrder);

			final CreditorSaleDetail creditorSaleDetailTemp = creditorSaleDetail;
			final CreditorTransferConfirmOrderDetail finalCreditorTransferConfirmOrderDetail = creditorTransferConfirmOrderDetail;

			TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
				@Override
				public void afterCommit() {
					super.afterCommit();

					try {
						// 发送债权转让协议签署消息
						consistencyRabbitTemplate.convertAndSend(MqConstant.CREDITOR_TRANSFER_PROTOCOL_SIGN_EXCHANGE,
								MqConstant.CREDITOR_TRANSFER_PROTOCOL_SIGN_CONTRACT, creditorSaleDetailTemp);
					}catch (Throwable e) {
						logger.error("发送债权转让协议消息异常 creditorSaleDetailId:{}", finalCreditorTransferConfirmOrderDetail.getCreditorSaleDetailId(), e);
					}

					// 债转确认成功记账
					try {
						creditorTransferConfirmSuccessAccounting(creditorSaleDetailTemp, projectInvestorPlanList);
					} catch (Throwable e) {
						logger.error("债转确认成功记账异常 creditorSaleDetailId:{}", finalCreditorTransferConfirmOrderDetail.getCreditorSaleDetailId(), e);
					}

					// 债权出让人投资红包处理
					try {
						creditorSellerInvestPrizeHandler(creditorSaleDetailTemp);
					} catch (Throwable e) {
						logger.error("债权出让人投资红包处理异常 creditorSaleDetailId:{}", finalCreditorTransferConfirmOrderDetail.getCreditorSaleDetailId(), e);
					}

					// 债权出让人标的加息处理
					try {
						creditorSellerProjectActivityRaiseInterestHandler(creditorSaleDetailTemp);
					} catch (Throwable e) {
						logger.error("债权出让人标的加息处理异常 creditorSaleDetailId:{}", finalCreditorTransferConfirmOrderDetail.getCreditorSaleDetailId(), e);
					}
				}
			});
		} else {
			// 债转确认通知状态异常。
			logger.error("债转确认通知状态异常 creditorSaleDetailId:{}, bathTransactionNotifyDTO.getStatus():{}", creditorTransferConfirmOrderDetail.getCreditorSaleDetailId(), bathTransactionNotifyDTO.getStatus());
			throw new BizException("ACC20004");
		}
	}

	/**
	 * 变更还款回款计划和投资人债权
	 * @param creditorSaleDetail
	 * @param projectInvestOrder
	 * @return
	 */
	@Transactional(propagation = Propagation.MANDATORY)
	public List<ProjectInvestorPlan> changeInvestorPlanAndInvestorCreditor(CreditorSaleDetail creditorSaleDetail, ProjectInvestOrder projectInvestOrder) {
        List<ProjectInvestorPlan> projectInvestorPlanList = new ArrayList<>();

        // 剩余总应收本金
		BigDecimal originCapital = BigDecimal.ZERO;
        List<ProjectInvestorPlan> originProjectInvestorPlanList = projectInvestorPlanMapperExt.listProjectInvestorPlanNotReceived(creditorSaleDetail.getInvestOrderId(), creditorSaleDetail.getProjectId());
        for(ProjectInvestorPlan originInvestorPlan : originProjectInvestorPlanList){
			originCapital = originCapital.add(originInvestorPlan.getCapital());
		}


		BigDecimal interest = BigDecimal.ZERO;
		int transferNum = 1;
        for(ProjectInvestorPlan originInvestorPlan : originProjectInvestorPlanList){
            // 源投资人回款计划更新为已转让
            ProjectInvestorPlan updateOriginInvestorPlan = new ProjectInvestorPlan();
            updateOriginInvestorPlan.setId(originInvestorPlan.getId());
            updateOriginInvestorPlan.setReceivedStatus(InvestorPlanReceivedStatusEnum.TRANSFERRED.getCode());
			updateOriginInvestorPlan.setOverCurrentDate(commonLocalService.getCurrentDate());
			updateOriginInvestorPlan.setOverTime(new Date());
			if((creditorSaleDetail.getSaleAmount().add(creditorSaleDetail.getSellingInterest())).compareTo(originCapital) > 0){
				// 出让价格大于剩余总应收本金 出让人还有收取到利息放在出让第一期
				if(transferNum == 1){
					updateOriginInvestorPlan.setReceivedInterest((creditorSaleDetail.getSaleAmount().add(creditorSaleDetail.getSellingInterest())).subtract(originCapital));
				}
				updateOriginInvestorPlan.setReceivedCapital(originInvestorPlan.getCapital());
			} else {
				// 出让价格小于等于剩余总应收本金 出让人没有可收取利息
				// 如果出让价格小于剩余总应收本金，出让第一期的实收本金=应收本金-(剩余总应收本金与出让价格的差值)
				if(transferNum == 1){
					updateOriginInvestorPlan.setReceivedCapital(originInvestorPlan.getCapital().subtract(originCapital.subtract((creditorSaleDetail.getSaleAmount().add(creditorSaleDetail.getSellingInterest())))));
				} else {
					updateOriginInvestorPlan.setReceivedCapital(originInvestorPlan.getCapital());
				}
			}

            projectInvestorPlanMapperExt.updateByPrimaryKeySelective(updateOriginInvestorPlan);

            ProjectInvestorPlan projectInvestorPlan = new ProjectInvestorPlan();
            projectInvestorPlan.setId(snowflakeIdWorker.nextId());
            projectInvestorPlan.setInvestOrderId(projectInvestOrder.getId());
			projectInvestorPlan.setInvestType(Byte.valueOf("2"));
			projectInvestorPlan.setOrgInvestOrderId(creditorSaleDetail.getInvestOrderId());
            projectInvestorPlan.setProjectId(originInvestorPlan.getProjectId());
            projectInvestorPlan.setOrgId(originInvestorPlan.getOrgId());
            projectInvestorPlan.setUserId(projectInvestOrder.getUserId());
            projectInvestorPlan.setAccountId(projectInvestOrder.getAccountId());
            projectInvestorPlan.setPlatformUserNo(projectInvestOrder.getPlatformUserNo());
            projectInvestorPlan.setCurrentPeriod(originInvestorPlan.getCurrentPeriod());
            projectInvestorPlan.setTotalPeriod(originInvestorPlan.getTotalPeriod());
            projectInvestorPlan.setReceivedDate(originInvestorPlan.getReceivedDate());
            projectInvestorPlan.setYearMouth(originInvestorPlan.getYearMouth());
            projectInvestorPlan.setPenaltyBeginDate(originInvestorPlan.getPenaltyBeginDate());
			projectInvestorPlan.setOrgPenaltyFee(BigDecimal.ZERO);
            projectInvestorPlan.setReceivedInterest(BigDecimal.ZERO);
            projectInvestorPlan.setReceivedCapital(BigDecimal.ZERO);
            projectInvestorPlan.setReceivedPenaltyFee(BigDecimal.ZERO);
			projectInvestorPlan.setTotalPenaltyFee(BigDecimal.ZERO);
            projectInvestorPlan.setCapital(originInvestorPlan.getCapital());
            projectInvestorPlan.setInterest(originInvestorPlan.getInterest());
            projectInvestorPlan.setReceivedStatus(InvestorPlanReceivedStatusEnum.NON_RECEIVE.getCode());
			projectInvestorPlan.setIsOld(originInvestorPlan.getIsOld());
            projectInvestorPlan.setInvestTime(projectInvestOrder.getCreateTime());
            projectInvestorPlan.setCreateTime(new Date());
            projectInvestorPlan.setUpdateTime(new Date());

            projectInvestorPlanMapperExt.insertSelective(projectInvestorPlan);
            projectInvestorPlanList.add(projectInvestorPlan);

            interest = interest.add(projectInvestorPlan.getInterest());
			transferNum++;
        }
        InvestorCreditor originInvestorCreditor = investorCreditorMapperExt.queryInvestorCreditorByInvestOrderId(creditorSaleDetail.getInvestOrderId());
        InvestorCreditor updateOriginInvestorCreditor = new InvestorCreditor();
        updateOriginInvestorCreditor.setId(originInvestorCreditor.getId());
		if((creditorSaleDetail.getSaleAmount().add(creditorSaleDetail.getSellingInterest())).compareTo(originCapital) > 0){
			updateOriginInvestorCreditor.setReceivedInterest(originInvestorCreditor.getReceivedInterest().add(((creditorSaleDetail.getSaleAmount().add(creditorSaleDetail.getSellingInterest())).subtract(originCapital))));
			updateOriginInvestorCreditor.setReceivedCapital(originInvestorCreditor.getReceivedCapital().add(originCapital));
		} else {
			updateOriginInvestorCreditor.setReceivedCapital(originInvestorCreditor.getReceivedCapital().add((creditorSaleDetail.getSaleAmount().add(creditorSaleDetail.getSellingInterest()))));
		}
        updateOriginInvestorCreditor.setStatus(InvestorCreditorStatusEnum.TRANSFERRED.getStatus());
        updateOriginInvestorCreditor.setTransferTime(new Date());
        investorCreditorMapperExt.updateByPrimaryKeySelective(updateOriginInvestorCreditor);

        InvestorCreditor investorCreditor = new InvestorCreditor();
        investorCreditor.setId(snowflakeIdWorker.nextId());
        investorCreditor.setInvestOrderId(projectInvestOrder.getId());
        investorCreditor.setProjectId(originInvestorCreditor.getProjectId());
        investorCreditor.setBorrowUserId(originInvestorCreditor.getBorrowUserId());
        investorCreditor.setProjectType(Byte.valueOf("3"));
        investorCreditor.setInvestUserId(projectInvestOrder.getUserId());
        investorCreditor.setBorrowRate(originInvestorCreditor.getBorrowRate());
        investorCreditor.setAddRate(projectInvestOrder.getAddRate());
        investorCreditor.setRepaymentType(originInvestorCreditor.getRepaymentType());
        investorCreditor.setTransferFrequency(originInvestorCreditor.getTransferFrequency() + 1);
        investorCreditor.setStatus(InvestorCreditorStatusEnum.NORMAL_RECEIVING.getStatus());
        investorCreditor.setCurrentPeriod(originInvestorCreditor.getCurrentPeriod());
        investorCreditor.setTotalPeriod(originInvestorCreditor.getTotalPeriod());
        investorCreditor.setReceivedPeriod(0);
        investorCreditor.setReceivedDate(originInvestorCreditor.getReceivedDate());
		investorCreditor.setCurrentInterest(originInvestorCreditor.getCurrentInterest());
        investorCreditor.setLastPeriodReceivedDate(originInvestorCreditor.getLastPeriodReceivedDate());
        investorCreditor.setExpectOverDate(originInvestorCreditor.getExpectOverDate());
		// 记录下出让人获得的利息
		BigDecimal creditorSellerInterest = projectInvestOrder.getAmount().subtract(originCapital);
		investorCreditor.setCreditorSellerInterest(creditorSellerInterest);
        investorCreditor.setCapital(originCapital);
        investorCreditor.setInterest(interest);
        investorCreditor.setTotalPenaltyFee(BigDecimal.ZERO);
        investorCreditor.setReceivedCapital(BigDecimal.ZERO);
        investorCreditor.setReceivedInterest(BigDecimal.ZERO);
        investorCreditor.setReceivedPenaltyFee(BigDecimal.ZERO);
        investorCreditor.setCreateTime(new Date());
        investorCreditor.setUpdateTime(new Date());
        investorCreditorMapperExt.insertSelective(investorCreditor);
        return projectInvestorPlanList;

	}

	/**
	 * 调用银行存管债转确认
	 *
	 * @param creditorSaleDetailId
	 * @param asyncTransactionRequest
	 */
	@Transactional( propagation = Propagation.REQUIRES_NEW)
	public void callBankCreditorTransferConfirm(Long creditorSaleDetailId, AsyncTransactionRequest asyncTransactionRequest) {
		logger.info("调用银行存管债转确认 creditorSaleDetailId:{}", creditorSaleDetailId);

		CompletableFuture<AsyncTransactionResponse> future = null;
		try {
			// 调用银行存管债转确认
			future = lanMaoDirectService.asyncTransaction(asyncTransactionRequest);
		} catch (Throwable e) {
			logger.error("调用银行存管批量债转确认异常 creditorSaleDetailId:{}", creditorSaleDetailId, e);
			throw e;
		}

		try {
			AsyncTransactionResponse response = future.get();
			if(response != null && !"100001".equals(response.getErrorCode())) {
				logger.info("调用银行存管债转确认结果 creditorSaleDetailId:{}, response:{}", creditorSaleDetailId, JSON.toJSON(response));
				if (ResponseCodeEnum.FAILURE.getValue().equals(response.getCode())) {// 调用失败
					((CreditorTransferConfirmLocalService) AopContext.currentProxy()).callBankTransferBackFailUpdateCreditorTransferConfirmDetailOrderStatus(asyncTransactionRequest, response.getErrorCode(), response.getErrorMessage());
					logger.error("调用银行存管债转确认失败 creditorSaleDetailId:{}; errorMessage : {}", creditorSaleDetailId, response.getErrorMessage());
					throw new BizException("ACC20002", "调用银行存管债转确认失败:" + response.getErrorMessage());
				} else {
					if (ResponseStatusEnum.INIT.getValue().equals(response.getStatus())) {// 处理失败
						((CreditorTransferConfirmLocalService) AopContext.currentProxy()).callBankTransferBackFailUpdateCreditorTransferConfirmDetailOrderStatus(asyncTransactionRequest, response.getErrorCode(), response.getErrorMessage());
						logger.error("调用银行存管债转确认失败 creditorSaleDetailId:{}; errorMessage : {}", creditorSaleDetailId, response.getErrorMessage());
						throw new BizException("ACC20001", "调用银行存管债转确认,银行返回业务处理失败:" + response.getErrorMessage());
					} else if (ResponseStatusEnum.SUCCESS.getValue().equals(response.getStatus())) {
						logger.info("调用银行存管债转确认成功 creditorSaleDetailId:{}", creditorSaleDetailId);
					}
				}
			} else {
				logger.warn("调用银行存管债转确认异常 creditorSaleDetailId:{}, response:{}", creditorSaleDetailId, JSON.toJSON(response));
			}
		} catch (InterruptedException e) {
			logger.error("调用银行存管债转确认异常 creditorSaleDetailId:{}", creditorSaleDetailId, e);
			throw new BizException("ACC20003", "调用银行存管债转确认异常");
		} catch (ExecutionException e) {
			logger.error("调用银行存管债转确认异常 creditorSaleDetailId:{}", creditorSaleDetailId, e);
			throw new BizException("ACC20003", "调用银行存管债转确认异常");
		}
	}

	/**
	 * 调用银行债转确认明确返回失败修改订单状态
	 * @param asyncTransactionRequest
	 * @param errorCode
	 * @param errorMessage
	 */
	@Transactional( propagation = Propagation.REQUIRES_NEW)
	public void callBankTransferBackFailUpdateCreditorTransferConfirmDetailOrderStatus(AsyncTransactionRequest asyncTransactionRequest, String errorCode, String errorMessage){
		for(AsyncTransactionRequest.BizDetail bizDetail : asyncTransactionRequest.getBizDetails()){
			CreditorTransferConfirmOrderDetail creditorTransferConfirmOrderDetail = creditorTransferConfirmOrderDetailMapperExt.queryCreditorTransferConfirmOrderDetailByDetailRequestNo(bizDetail.getRequestNo());
			creditorTransferConfirmOrderDetail = creditorTransferConfirmOrderDetailMapperExt.selectByPrimaryKeyForUpdate(creditorTransferConfirmOrderDetail.getId());
			CreditorTransferConfirmOrderDetail updateRecord = new CreditorTransferConfirmOrderDetail();
			updateRecord.setId(creditorTransferConfirmOrderDetail.getId());
			updateRecord.setStatus(CreditorTransferConfirmStatusEnum.FAIL.getValue());
			updateRecord.setErrorCode(errorCode);
			updateRecord.setErrorMessage(errorMessage);
			creditorTransferConfirmOrderDetailMapperExt.updateByPrimaryKeySelective(updateRecord);
		}
	}

	/**
	 * 查询银行债转确认结果
	 *
	 * @param detailRequestNo
	 * @param creditorSaleDetailId
	 * @return
	 */
	private BathTransactionNotifyDTO queryBankCreditorTransferConfirmResult(String detailRequestNo, Long creditorSaleDetailId) {
		logger.info("调用银行查询债转确认结果 creditorSaleDetailId:{}", creditorSaleDetailId);
		CompletableFuture<QueryTransactionResponse> future = null;
		try {
			QueryTransactionRequest request = new QueryTransactionRequest();
			request.setRequestNo(detailRequestNo);
			request.setTransactionType(TradeQueryTypeEnum.TRANSACTION);
			future = lanMaoDirectService.queryTransaction(request);
		} catch (Throwable e) {
			logger.error("调用银行存管查询交易结果异常 creditorSaleDetailId:{}", creditorSaleDetailId, e);
			throw new BizException("ACC20009", e.getMessage());
		}

		try {
			QueryTransactionResponse response = future.get();
			logger.info("查询银行债转确认结果 creditorSaleDetailId:{}; response:{}", creditorSaleDetailId, JSON.toJSON(response));
			if (ResponseCodeEnum.SUCCESS.getValue().equals(response.getCode())) {
				List<QueryTransactionResponse.TransactionDetail> records = response.getRecords();
				if (records == null || records.isEmpty() || records.get(0) == null) {
					throw new BizException("ACC20009", "调用银行存管查询交易结果失败:" + response.getErrorMessage());
				}
				BathTransactionNotifyDTO result = new BathTransactionNotifyDTO();
				result.setAsyncRequestNo(detailRequestNo);

				TransationStatusEnum status = TransationStatusEnum.enumOf(records.get(0).getStatus());
				switch (status) {
					case SUCCESS:
						result.setStatus(CreditorTransferConfirmStatusEnum.SUCCESS.name());
						return result;
					case FAIL:
						logger.warn("查询银行债转确认结果 银行存管返回状态为处理失败  creditorSaleDetailId:{}, records.get(0): {}", creditorSaleDetailId, JSON.toJSON(records.get(0)));
						result.setStatus(CreditorTransferConfirmStatusEnum.FAIL.name());
						result.setErrorCode(records.get(0).getErrorCode());
						result.setErrorMessage(records.get(0).getErrorMessage());
						return result;
					case ERROR:
						logger.warn("查询银行债转确认结果 银行存管返回状态为处理异常  creditorSaleDetailId:{}, records.get(0): {}", creditorSaleDetailId, JSON.toJSON(records.get(0)));
						result.setStatus(CreditorTransferConfirmStatusEnum.FAIL.name());
						result.setErrorCode(records.get(0).getErrorCode());
						result.setErrorMessage(records.get(0).getErrorMessage());
						return result;
					default:
						logger.info("查询银行债转确认结果 银行存管返回状态为处理中  creditorSaleDetailId:{}, records.get(0): {}", creditorSaleDetailId, JSON.toJSON(records.get(0)));
						throw new BizException("ACC20010", "调用银行存管查询交易结果,银行返回处理中:" + response.getErrorMessage());
				}
			} else {
				// 100007 查询对象不存在，需要重新发起债转确认
				if ("100007".equals(response.getErrorCode())) {
					logger.error("查询银行债转确认结果不存在 creditorSaleDetailId:{}; response:{}", creditorSaleDetailId, JSON.toJSON(response));
					((CreditorTransferConfirmLocalService)AopContext.currentProxy()).orderNotFound(detailRequestNo, response.getErrorCode(), response.getErrorMessage());
					throw new BizException("ACC20008", "查询银行债转确认结果不存在:" + response.getErrorMessage());
				} else {
					// 调用查询失败
					logger.error("查询银行债转确认结果失败 creditorSaleDetailId:{}; response:{}", creditorSaleDetailId, JSON.toJSON(response));
					throw new BizException("ACC20009", "调用银行存管查询交易结果失败:" + response.getErrorMessage());
				}
			}
		} catch (InterruptedException e) {
			logger.error("调用银行存管查询交易结果异常 creditorSaleDetailId:{}", creditorSaleDetailId, e);
			throw new BizException("ACC20011", "调用银行存管查询交易结果异常");
		} catch (ExecutionException e) {
			logger.error("调用银行存管查询交易结果异常 creditorSaleDetailId:{}", creditorSaleDetailId, e);
			throw new BizException("ACC20011", "调用银行存管查询交易结果异常");
		}
	}

	/**
	 * 订单不存在修改订单明细状态
	 *
	 * @param detailRequestNo
	 * @param errorCode
	 * @param errorMessage
	 */
	@Transactional
	public void orderNotFound(String detailRequestNo, String errorCode, String errorMessage){
		CreditorTransferConfirmOrderDetail creditorTransferConfirmOrderDetail = creditorTransferConfirmOrderDetailMapperExt.queryCreditorTransferConfirmOrderDetailByDetailRequestNo(detailRequestNo);
		creditorTransferConfirmOrderDetail = creditorTransferConfirmOrderDetailMapperExt.selectByPrimaryKeyForUpdate(creditorTransferConfirmOrderDetail.getId());
		if(creditorTransferConfirmOrderDetail.getCreateTime().before(new DateTime().minusMinutes(20).toDate())){
			CreditorTransferConfirmOrderDetail updateRecord = new CreditorTransferConfirmOrderDetail();
			updateRecord.setId(creditorTransferConfirmOrderDetail.getId());
			updateRecord.setStatus(CreditorTransferConfirmStatusEnum.FAIL.getValue());
			updateRecord.setErrorCode(errorCode);
			updateRecord.setErrorMessage(errorMessage);
			creditorTransferConfirmOrderDetailMapperExt.updateByPrimaryKeySelective(updateRecord);
		}
	}

	/**
	 * 债转确认成功记账操作
	 * @param creditorSaleDetail
	 * @param projectInvestorPlanList
	 */
	private void creditorTransferConfirmSuccessAccounting(CreditorSaleDetail creditorSaleDetail, List<ProjectInvestorPlan> projectInvestorPlanList){
		logger.info("债转确认处理成功， creditorSaleDetailId:{}", creditorSaleDetail.getId());
		CreditorTransferSuccessAccountingRequestDTO requestDTO = new CreditorTransferSuccessAccountingRequestDTO();
		requestDTO.setSaleDetailId(creditorSaleDetail.getId());
		requestDTO.setRequestNo(creditorSaleDetail.getRequestNo());

		StringBuilder saleDetailTitle = new StringBuilder("债权转让-");
		if(creditorSaleDetail.getRemainingDeadlineMonth() > 0){
			saleDetailTitle.append(creditorSaleDetail.getRemainingDeadlineMonth()).append("个月");
		}
		if(creditorSaleDetail.getRemainingDeadlineDay() > 0){
			saleDetailTitle.append(creditorSaleDetail.getRemainingDeadlineDay()).append("天");
		}
		saleDetailTitle.append("（").append(creditorSaleDetail.getBorrowRate().multiply(BigDecimal.valueOf(100)).stripTrailingZeros().toPlainString()).append("%）");
		requestDTO.setSaleDetailTitle(saleDetailTitle.toString());
		requestDTO.setSaleUserId(creditorSaleDetail.getUserId());

		List<CreditorTransferConfirmOrderDetailBiz> creditorTransferConfirmOrderDetailBizList = creditorTransferConfirmOrderDetailBizMapperExt.querySuccessCreditorTransferConfirmOrderDetailBizByCreditorSaleDetailId(creditorSaleDetail.getId());
		for (CreditorTransferConfirmOrderDetailBiz creditorTransferConfirmOrderDetailBiz : creditorTransferConfirmOrderDetailBizList) {
			if(BusinessTypeEnum.CREDIT_ASSIGNMENT.getValue().equals(creditorTransferConfirmOrderDetailBiz.getBizType())) {
				requestDTO.setInvestOrderId(creditorTransferConfirmOrderDetailBiz.getInvestOrderId());
				requestDTO.setInvestUserId(creditorTransferConfirmOrderDetailBiz.getSourceUserId());
				requestDTO.setTransferAmount(creditorTransferConfirmOrderDetailBiz.getAmount());
			}else if(BusinessTypeEnum.COMMISSION.getValue().equals(creditorTransferConfirmOrderDetailBiz.getBizType())){
				requestDTO.setTransferManagementFee(creditorTransferConfirmOrderDetailBiz.getAmount());
			}
		}

		BigDecimal dueInCorpusAmount = BigDecimal.ZERO;
		BigDecimal dueInInterestAmount = BigDecimal.ZERO;
        for (ProjectInvestorPlan projectInvestorPlan : projectInvestorPlanList){
			dueInCorpusAmount = dueInCorpusAmount.add(projectInvestorPlan.getCapital());
			dueInInterestAmount = dueInInterestAmount.add(projectInvestorPlan.getInterest());
        }
		requestDTO.setDueInCorpusAmount(dueInCorpusAmount);
		requestDTO.setDueInInterestAmount(dueInInterestAmount);


		try {
			logger.info("调用账务中心记账开始 requestDTO:{}", JSON.toJSONString(requestDTO));
			creditorTransferDubboService.transferSuccessAccounting(requestDTO);
			logger.info("调用账务中心记账成功 requestDTO:{}", JSON.toJSONString(requestDTO));
			((CreditorTransferConfirmLocalService)AopContext.currentProxy()).updateCreditorSaleAccountingSuccessful(creditorSaleDetail.getId(), creditorSaleDetail.getUserId());
		}catch (Exception e){
			logger.error("调用账务中心记账失败 requestDTO:{}", JSON.toJSONString(requestDTO),e);
		}
	}

	/**
	 * 更新债转确认记账成功
	 * @param creditorSaleDetailId
	 */
	@Transactional( propagation = Propagation.REQUIRES_NEW)
	public void updateCreditorSaleAccountingSuccessful(Long creditorSaleDetailId, String creditorSaleUserId){
		logger.info("调用账务中心记账成功，更新记账状态 creditorSaleDetailId:{}", creditorSaleDetailId);
		CreditorSaleDetail creditorSaleDetail = new CreditorSaleDetail();
		creditorSaleDetail.setId(creditorSaleDetailId);
		creditorSaleDetail.setUserId(creditorSaleUserId);
		creditorSaleDetail.setAccountingStatus(CreditorTransferConfirmStatusEnum.SUCCESS.getValue());
		creditorSaleDetailMapperExt.updateByPrimaryKeyAndUserIdSelective(creditorSaleDetail);
	}

	/**
	 * 债权出让人投资红包处理
	 *
	 * @param creditorSaleDetail
	 */
	private void creditorSellerInvestPrizeHandler(CreditorSaleDetail creditorSaleDetail){
		ProjectInvestOrder projectInvestOrder = projectInvestOrderMapperExt.selectByPrimaryKey(creditorSaleDetail.getInvestOrderId());
		if (projectInvestOrder.getPrizeId() != null && UserPrizeTypeIdEnum.INVESTMENT_RAISE_INTEREST_RATES.getPrizeType().equals(
				projectInvestOrder.getPrizeTypteId())) {
			InvestorCreditor investorCreditor = investorCreditorMapperExt.queryInvestorCreditorByInvestOrderId(creditorSaleDetail.getInvestOrderId());

			PrizeToBackedForCreditorSaleReqDTO prizeToBackedForCreditorSaleReqDTO = new PrizeToBackedForCreditorSaleReqDTO();
			prizeToBackedForCreditorSaleReqDTO.setUserId(projectInvestOrder.getUserId());
			prizeToBackedForCreditorSaleReqDTO.setProjectId(projectInvestOrder.getProjectId());
			prizeToBackedForCreditorSaleReqDTO.setInvestOrderId(projectInvestOrder.getId());
			prizeToBackedForCreditorSaleReqDTO.setPrizeId(projectInvestOrder.getPrizeId());
			prizeToBackedForCreditorSaleReqDTO.setCurrentPeriod(investorCreditor.getCurrentPeriod());
			prizeToBackedForCreditorSaleReqDTO.setCurrentPeriodDays(RepaymentUtil.getOverdueDay(investorCreditor.getLastPeriodReceivedDate(), investorCreditor.getReceivedDate()));
			prizeToBackedForCreditorSaleReqDTO.setCurrentPeriodHoldDays(RepaymentUtil.getOverdueDay(investorCreditor.getLastPeriodReceivedDate(), creditorSaleDetail.getSuccessTime()) - 1);

			logger.info("prizeHandler creditorSaleDetail:{}, prizeToBackedForCreditorSaleReqDTO:{}", JSON.toJSON(creditorSaleDetail), JSON.toJSON(prizeToBackedForCreditorSaleReqDTO));
			activityPrizeDubboService.prizeToBackedForCreditorSale(prizeToBackedForCreditorSaleReqDTO);
		}

		((CreditorTransferConfirmLocalService)AopContext.currentProxy()).updateCreditorSellerInvestPrizeStatus(creditorSaleDetail.getId(), creditorSaleDetail.getUserId());
	}

	/**
	 * 更新债转确认债权出让人投资红包处理状态
	 * @param creditorSaleDetailId
	 */
	@Transactional( propagation = Propagation.REQUIRES_NEW)
	public void updateCreditorSellerInvestPrizeStatus(Long creditorSaleDetailId, String creditorSaleUserId){
		CreditorSaleDetail creditorSaleDetail = new CreditorSaleDetail();
		creditorSaleDetail.setId(creditorSaleDetailId);
		creditorSaleDetail.setUserId(creditorSaleUserId);
		creditorSaleDetail.setSellerInvestPrizeStatus(CreditorTransferConfirmStatusEnum.SUCCESS.getValue());
		creditorSaleDetailMapperExt.updateByPrimaryKeyAndUserIdSelective(creditorSaleDetail);
	}

	/**
	 * 债权出让人标的加息处理
	 *
	 * @param creditorSaleDetail
	 */
	private void creditorSellerProjectActivityRaiseInterestHandler(CreditorSaleDetail creditorSaleDetail){
		Project project = projectMapperExt.selectByPrimaryKey(creditorSaleDetail.getProjectId());

		if (project.getActivityRaiseRate() != null && project.getActivityRaiseRate().compareTo(BigDecimal.ZERO) > 0) {
			InvestorCreditor investorCreditor = investorCreditorMapperExt.queryInvestorCreditorByInvestOrderId(creditorSaleDetail.getInvestOrderId());

			ProjectRaiseRateCreditorReqDTO projectRaiseRateCreditorReqDTO = new ProjectRaiseRateCreditorReqDTO();
			projectRaiseRateCreditorReqDTO.setUserId(investorCreditor.getInvestUserId());
			projectRaiseRateCreditorReqDTO.setInvestOrderId(investorCreditor.getInvestOrderId());
			projectRaiseRateCreditorReqDTO.setCurrentPeriod(investorCreditor.getCurrentPeriod());
			projectRaiseRateCreditorReqDTO.setCurrentPeriodDays(RepaymentUtil.getOverdueDay(investorCreditor.getLastPeriodReceivedDate(), investorCreditor.getReceivedDate()));
			projectRaiseRateCreditorReqDTO.setCurrentPeriodHoldDays(RepaymentUtil.getOverdueDay(investorCreditor.getLastPeriodReceivedDate(), creditorSaleDetail.getSuccessTime()) - 1);

			logger.info("creditorSellerProjectActivityRaiseInterestHandler creditorSaleDetail:{}, projectRaiseRateCreditorReqDTO:{}", JSON.toJSON(creditorSaleDetail), JSON.toJSON(projectRaiseRateCreditorReqDTO));
			projectRaiseRateDubboService.creditorProjectRaiseRate(projectRaiseRateCreditorReqDTO);
		}

		((CreditorTransferConfirmLocalService)AopContext.currentProxy()).updateCreditorSellerProjectActivityRaiseInterestStatus(creditorSaleDetail.getId(), creditorSaleDetail.getUserId());
	}

	/**
	 * 更新债转确认债权出让人标的加息处理状态
	 * @param creditorSaleDetailId
	 */
	@Transactional( propagation = Propagation.REQUIRES_NEW)
	public void updateCreditorSellerProjectActivityRaiseInterestStatus(Long creditorSaleDetailId, String creditorSaleUserId){
		CreditorSaleDetail creditorSaleDetail = new CreditorSaleDetail();
		creditorSaleDetail.setId(creditorSaleDetailId);
		creditorSaleDetail.setUserId(creditorSaleUserId);
		creditorSaleDetail.setSellerProjectActivityRaiseInterestStatus(CreditorTransferConfirmStatusEnum.SUCCESS.getValue());
		creditorSaleDetailMapperExt.updateByPrimaryKeyAndUserIdSelective(creditorSaleDetail);
	}

	/**
	 * 债权转让协议
	 *
	 * @param creditorSaleDetail
	 */
	public void creditorTransferProtocol(CreditorSaleDetail creditorSaleDetail) throws Exception {
		if(creditorSaleDetail == null){
			throw new BizException("TRD10005", "债权转让协议处理处理异常 creditorSaleDetail is null");
		}
		String bizContractNo = "ZQ" + FastDateFormat.getInstance("yyMMdd").format(new Date()) + creditorSaleDetail.getId();
		ProjectContract creditorTransferProtocol = projectContractMapperExt.queryProjectContractByProjectIdAndContractType(creditorSaleDetail.getId(), TemplateTypeEnum.CREDITOR_TRANSFER_PROTOCOL.getType());
		if (creditorTransferProtocol == null) {
			creditorTransferProtocol = fadadaContractContext.initContractRecord(creditorSaleDetail.getId(),
					creditorSaleDetail.getUserId(), bizContractNo, TemplateTypeEnum.CREDITOR_TRANSFER_PROTOCOL.getType(),
					TradeTypeEnum.CREDITOR_TRANSFER.getType(), creditorSaleDetail.getId());
			((CreditorTransferConfirmLocalService) AopContext.currentProxy()).saveLendContractInitData(creditorTransferProtocol);
		}

		if (StringUtils.isBlank(creditorTransferProtocol.getViewUrl()) && StringUtils.isBlank(creditorTransferProtocol.getDownloadUrl())) {
			ProjectInvestOrder projectInvestOrder = projectInvestOrderMapperExt.queryInvestSuccessfulByCreditorSaleDetailId(creditorSaleDetail.getId());
			ProjectContract creditorTransferProtocolSigned = creditorTransferContract
					.contractHandler(TemplateTypeEnum.CREDITOR_TRANSFER_PROTOCOL, projectInvestOrder.getUserId(), creditorSaleDetail);
			creditorTransferProtocolSigned.setId(creditorTransferProtocol.getId());
			((CreditorTransferConfirmLocalService) AopContext.currentProxy()).updateProjectContract(creditorTransferProtocolSigned);
		}
	}

	@Transactional
	public void updateProjectContract(ProjectContract projectContract) {
		projectContractMapperExt.updateByPrimaryKeySelective(projectContract);
	}

	@Transactional
	public void saveLendContractInitData(ProjectContract projectContract) {
		projectContractMapperExt.insertSelective(projectContract);
	}

	public void bankCreditorTransferConfirmResultQueryJob() {
		logger.info("银行债转确认结果查询...");
		List<CreditorTransferConfirmOrderDetail> creditorTransferConfirmOrderDetailList = creditorTransferConfirmOrderDetailMapperExt.queryCreditorTransferConfirmOrderDetailByBankTransferResultQueryJob();
		if(creditorTransferConfirmOrderDetailList != null){
			for (CreditorTransferConfirmOrderDetail creditorTransferConfirmOrderDetail : creditorTransferConfirmOrderDetailList) {
				if (creditorTransferConfirmOrderDetail != null) {
					logger.info("银行债转确认结果查询 creditorTransferConfirmOrderDetail:{}", JSON.toJSON(creditorTransferConfirmOrderDetail));
					try {
						BathTransactionNotifyDTO bathTransactionNotifyDTO = queryBankCreditorTransferConfirmResult(creditorTransferConfirmOrderDetail.getDetailRequestNo(), creditorTransferConfirmOrderDetail.getCreditorSaleDetailId());
						((CreditorTransferConfirmLocalService)AopContext.currentProxy()).creditorTransferConfirmResultNotify(bathTransactionNotifyDTO);
					} catch (Throwable e) {
						logger.error("银行债转确认结果查询执行异常 creditorTransferConfirmOrderDetail:{}", JSON.toJSON(creditorTransferConfirmOrderDetail), e);
					}
				}
			}
		}
	}

	public void bankCreditorTransferConfirmFailedJob() {
		logger.info("银行债转确认失败任务...");

		List<CreditorTransferConfirmOrderDetail> creditorTransferConfirmOrderDetailList = creditorTransferConfirmOrderDetailMapperExt.queryCreditorTransferConfirmOrderDetailByBankTransferFailedJob();
		if(creditorTransferConfirmOrderDetailList != null){
			for (CreditorTransferConfirmOrderDetail creditorTransferConfirmOrderDetail : creditorTransferConfirmOrderDetailList) {
				if (creditorTransferConfirmOrderDetail != null) {
					logger.info("银行债转确认失败任务 creditorTransferConfirmOrderDetail:{}", JSON.toJSON(creditorTransferConfirmOrderDetail));
					try {
                        ((CreditorTransferConfirmLocalService)AopContext.currentProxy()).bankCreditorTransferConfirmFailed(creditorTransferConfirmOrderDetail);
					} catch (Throwable e) {
						logger.error("银行债转确认失败任务执行异常 creditorTransferConfirmOrderDetail:{}", JSON.toJSON(creditorTransferConfirmOrderDetail), e);
					}
				}
			}
		}
	}

	@Transactional
	public void bankCreditorTransferConfirmFailed(CreditorTransferConfirmOrderDetail creditorTransferConfirmOrderDetail){
	    // 根据creditorSaleDetailId查询出该债权确认失败的债转确认明细
		logger.info("银行债转确认失败修改订单，重新发起债转确认 creditorTransferConfirmOrderDetail:{}", JSON.toJSON(creditorTransferConfirmOrderDetail));
        List<AsyncTransactionRequest.BizDetail> bizDetailList = new ArrayList<>();
        String newBatchNo = lanMaoSequence.getBatchNo();

		List<CreditorTransferConfirmOrderDetailBiz> creditorTransferConfirmOrderDetailBizList = creditorTransferConfirmOrderDetailBizMapperExt.queryCreditorTransferConfirmOrderDetailBizByDetailRequestNo(creditorTransferConfirmOrderDetail.getDetailRequestNo());

		String newDetailRequestNo = lanMaoSequence.getRequestNo();

		AsyncTransactionRequest.BizDetail bizDetail = new AsyncTransactionRequest.BizDetail();
		bizDetail.setRequestNo(newDetailRequestNo);
		bizDetail.setTradeType(TransactionTypeEnum.CREDIT_ASSIGNMENT);
		bizDetail.setProjectNo(creditorTransferConfirmOrderDetail.getProjectId() + "");
		bizDetail.setSaleRequestNo(creditorTransferConfirmOrderDetail.getCreditorSaleRequestNo());
		List<AsyncTransactionRequest.BizDetail.BusinessDetail> businessDetailList = new ArrayList<>();

		for (CreditorTransferConfirmOrderDetailBiz creditorTransferConfirmOrderDetailBiz : creditorTransferConfirmOrderDetailBizList) {
			// 写入新业务明细存管流水号
			CreditorTransferConfirmOrderDetailBiz newCreditorTransferConfirmOrderDetailBiz = new CreditorTransferConfirmOrderDetailBiz();
			newCreditorTransferConfirmOrderDetailBiz.setId(snowflakeIdWorker.nextId());
			newCreditorTransferConfirmOrderDetailBiz.setDetailRequestNo(newDetailRequestNo);
			newCreditorTransferConfirmOrderDetailBiz.setBizType(creditorTransferConfirmOrderDetailBiz.getBizType());
			newCreditorTransferConfirmOrderDetailBiz.setFreezeRequestNo(creditorTransferConfirmOrderDetailBiz.getFreezeRequestNo());
			newCreditorTransferConfirmOrderDetailBiz.setInvestOrderId(creditorTransferConfirmOrderDetailBiz.getInvestOrderId());
			newCreditorTransferConfirmOrderDetailBiz.setSourceUserId(creditorTransferConfirmOrderDetailBiz.getSourceUserId());
			newCreditorTransferConfirmOrderDetailBiz.setSourceAccountId(creditorTransferConfirmOrderDetailBiz.getSourceAccountId());
			newCreditorTransferConfirmOrderDetailBiz.setSourcePlatformUserNo(creditorTransferConfirmOrderDetailBiz.getSourcePlatformUserNo());
			newCreditorTransferConfirmOrderDetailBiz.setTargetUserId(creditorTransferConfirmOrderDetailBiz.getTargetUserId());
			newCreditorTransferConfirmOrderDetailBiz.setTargetAccountId(creditorTransferConfirmOrderDetailBiz.getTargetAccountId());
			newCreditorTransferConfirmOrderDetailBiz.setTargetPlatformUserNo(creditorTransferConfirmOrderDetailBiz.getTargetPlatformUserNo());
			newCreditorTransferConfirmOrderDetailBiz.setAmount(creditorTransferConfirmOrderDetailBiz.getAmount());
			newCreditorTransferConfirmOrderDetailBiz.setShare(creditorTransferConfirmOrderDetailBiz.getShare());
			newCreditorTransferConfirmOrderDetailBiz.setCreateTime(new Date());
			newCreditorTransferConfirmOrderDetailBiz.setUpdateTime(new Date());

			creditorTransferConfirmOrderDetailBizMapperExt.insertSelective(newCreditorTransferConfirmOrderDetailBiz);

			AsyncTransactionRequest.BizDetail.BusinessDetail businessDetail = new AsyncTransactionRequest.BizDetail.BusinessDetail();
			BusinessTypeEnum bizType = BusinessTypeEnum.enumOf(newCreditorTransferConfirmOrderDetailBiz.getBizType());
			businessDetail.setBizType(bizType);
			businessDetail.setFreezeRequestNo(newCreditorTransferConfirmOrderDetailBiz.getFreezeRequestNo());
			businessDetail.setSourcePlatformUserNo(newCreditorTransferConfirmOrderDetailBiz.getSourcePlatformUserNo());
			businessDetail.setTargetPlatformUserNo(newCreditorTransferConfirmOrderDetailBiz.getTargetPlatformUserNo());
			businessDetail.setAmount(newCreditorTransferConfirmOrderDetailBiz.getAmount());
			businessDetail.setShare(newCreditorTransferConfirmOrderDetailBiz.getShare());
			businessDetailList.add(businessDetail);
		}
		bizDetail.setDetails(businessDetailList);
		bizDetailList.add(bizDetail);

		// 原债转确认明细作废，写入新原债转确认明细
		CreditorTransferConfirmOrderDetail oldCreditorTransferConfirmOrderDetail = new CreditorTransferConfirmOrderDetail();
		oldCreditorTransferConfirmOrderDetail.setId(creditorTransferConfirmOrderDetail.getId());
		oldCreditorTransferConfirmOrderDetail.setStatus(CreditorTransferConfirmStatusEnum.DISABLED.getValue());
		creditorTransferConfirmOrderDetailMapperExt.updateByPrimaryKeySelective(oldCreditorTransferConfirmOrderDetail);


		CreditorTransferConfirmOrderDetail newCreditorTransferConfirmOrderDetail = new CreditorTransferConfirmOrderDetail();
		newCreditorTransferConfirmOrderDetail.setId(snowflakeIdWorker.nextId());
		newCreditorTransferConfirmOrderDetail.setBatchNo(newBatchNo);
		newCreditorTransferConfirmOrderDetail.setProjectId(creditorTransferConfirmOrderDetail.getProjectId());
		newCreditorTransferConfirmOrderDetail.setCreditorSaleDetailId(creditorTransferConfirmOrderDetail.getCreditorSaleDetailId());
		newCreditorTransferConfirmOrderDetail.setCreditorSaleUserId(creditorTransferConfirmOrderDetail.getCreditorSaleUserId());
		newCreditorTransferConfirmOrderDetail.setDetailRequestNo(newDetailRequestNo);
		newCreditorTransferConfirmOrderDetail.setCreditorSaleRequestNo(creditorTransferConfirmOrderDetail.getCreditorSaleRequestNo());
		newCreditorTransferConfirmOrderDetail.setStatus(CreditorTransferConfirmStatusEnum.HANDLING.getValue());
		newCreditorTransferConfirmOrderDetail.setAmountTotal(creditorTransferConfirmOrderDetail.getAmountTotal());
		newCreditorTransferConfirmOrderDetail.setNumTotal(creditorTransferConfirmOrderDetail.getNumTotal());
		newCreditorTransferConfirmOrderDetail.setCreateTime(new Date());
		newCreditorTransferConfirmOrderDetail.setUpdateTime(new Date());
		creditorTransferConfirmOrderDetailMapperExt.insertSelective(newCreditorTransferConfirmOrderDetail);


        // 银行存管业务明细
        AsyncTransactionRequest asyncTransactionRequest = new AsyncTransactionRequest();
        asyncTransactionRequest.setBatchNo(newBatchNo);
        asyncTransactionRequest.setBizDetails(bizDetailList);

        logger.info("银行债转确认失败修改订单，重新发起债转确认 债转确认订单构建成功 creditorTransferConfirmOrderDetail:{}, asyncTransactionRequest:{}", JSON.toJSON(creditorTransferConfirmOrderDetail), JSON.toJSON(asyncTransactionRequest));

        //调用银行存管债转确认
        TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
            @Override
            public void afterCommit() {
                super.afterCommit();
                // 调用银行存管债转确认
				callBankCreditorTransferConfirm(creditorTransferConfirmOrderDetail.getCreditorSaleDetailId(), asyncTransactionRequest);
            }
        });
	}

	public void accountingStatusJob() {
		logger.info("债转确认记账任务...");
		List<CreditorSaleDetail> creditorSaleDetailList = creditorSaleDetailMapperExt.queryCreditorSaleDetailByAccountingStatusJob();
		if(creditorSaleDetailList != null){
			for (CreditorSaleDetail creditorSaleDetail : creditorSaleDetailList) {
				if (creditorSaleDetail != null) {
					logger.info("债转确认记账任务 creditorSaleDetail:{}", JSON.toJSON(creditorSaleDetail));
					try {
						List<ProjectInvestorPlan> projectInvestorPlanList = projectInvestorPlanMapperExt.queryProjectInvestorPlanByProjectId(creditorSaleDetail.getProjectId());
						creditorTransferConfirmSuccessAccounting(creditorSaleDetail, projectInvestorPlanList);
					} catch (Throwable e) {
						logger.error("债转确认记账任务执行异常 creditorSaleDetail:{}", JSON.toJSON(creditorSaleDetail), e);
					}
				}
			}
		}
	}

	public void sellerInvestPrizeStatusJob() {
		logger.info("债转出让人投资红包处理任务...");
		List<CreditorSaleDetail> creditorSaleDetailList = creditorSaleDetailMapperExt.queryCreditorSaleDetailBySellerInvestPrizeStatusJob();
		if(creditorSaleDetailList != null){
			for (CreditorSaleDetail creditorSaleDetail : creditorSaleDetailList) {
				if (creditorSaleDetail != null) {
					logger.info("债转出让人投资红包处理任务 creditorSaleDetail:{}", JSON.toJSON(creditorSaleDetail));
					try {
						creditorSellerInvestPrizeHandler(creditorSaleDetail);
					} catch (Throwable e) {
						logger.error("债转出让人投资红包处理任务执行异常 creditorSaleDetail:{}", JSON.toJSON(creditorSaleDetail), e);
					}
				}
			}
		}
	}

	public void sellerProjectActivityRaiseInterestStatusJob() {
		logger.info("债权出让人标的加息处理任务...");
		List<CreditorSaleDetail> creditorSaleDetailList = creditorSaleDetailMapperExt.queryCreditorSaleDetailBySellerProjectActivityRaiseInterestStatusJob();
		if(creditorSaleDetailList != null){
			for (CreditorSaleDetail creditorSaleDetail : creditorSaleDetailList) {
				if (creditorSaleDetail != null) {
					logger.info("债权出让人标的加息处理任务 creditorSaleDetail:{}", JSON.toJSON(creditorSaleDetail));
					try {
						creditorSellerProjectActivityRaiseInterestHandler(creditorSaleDetail);
					} catch (Throwable e) {
						logger.error("债权出让人标的加息处理任务执行异常 creditorSaleDetail:{}", JSON.toJSON(creditorSaleDetail), e);
					}
				}
			}
		}
	}

	/**
	 * 查询主库设置
	 */
	private void queryForMaster() {
		if (!HintManagerHolder.isMasterRouteOnly()) {
			HintManager hintManager = HintManager.getInstance();
			hintManager.setMasterRouteOnly();
		}
	}

	public CreditorTransferConfirmOrderDetailBiz getCreditorTransferConfirmOrderDetailBiz(String requestNo,Byte bizType){
		CreditorTransferConfirmOrderDetailBiz creditorTransferConfirmOrderDetailBiz = creditorTransferConfirmOrderDetailBizMapperExt.queryCreditorTransferConfirmOrderDetailBizByDetailRequestNoBizType(requestNo,bizType);
		return creditorTransferConfirmOrderDetailBiz;
	}

	public CreditorTransferConfirmOrderDetail getCreditorTransferConfirmOrderDetail(String requestNo){
		CreditorTransferConfirmOrderDetail creditorTransferConfirmOrderDetail = creditorTransferConfirmOrderDetailMapperExt.queryCreditorTransferConfirmOrderDetailByDetailRequestNo(requestNo);
		return creditorTransferConfirmOrderDetail;
	}
}